
#include <stdlib.h>
#include <string.h>
#include <stdarg.h>
#include "alloc.h"
#include "str.h"
#define LOG_TAG "String"
#include "log.h"

#define NAME_HASH_MASK 1023
#define FORMAT_PRINT_BUFFER_SIZE 1024

typedef struct nameBucket
{
    char *name;
    int len;
    struct nameBucket *link;
} *NameBucket;

static NameBucket NameBuckets[NAME_HASH_MASK + 1];
int SoleIndex = 0;

/**
    The hash function for calculating hash value.
    源于Unix系统的ElfHash()哈希函数
 */
static unsigned int ELFHash(const char *str, int len)
{
    unsigned int h = 0;
    unsigned int x = 0;
    int i;

    for (i = 0; i < len; ++i)
    {
        h = (h << 4) + *str++;
        if ((x = h & 0xF0000000) != 0)
        {
            h ^= x >> 24;
            h &= ~x;
        }
    }

    return h;
}

/**
 * 初始化字符串资源池
 */
void InitString()
{
    memset(NameBuckets, 0, sizeof(NameBuckets));
}

const char* InternName(const char *id, int len)
{
    NameBucket p;

    if (id == NULL) {
        return NULL;
    } else if (len < 0) {
        len = strlen(id);
    }

    // 在哈希表中寻找是否已经存在同名标志符
    int h = ELFHash(id, len) & NAME_HASH_MASK;
    for (p = NameBuckets[h]; p != NULL; p = p->link) {
        if (len == p->len && strncmp(id, p->name, len) == 0) {
            return p->name;
        }
    }

    // 当不存在同名标志符时,申请堆内存
    ALLOC(p);
    // allocate memory for string
    p->name = HeapAllocate(MainHeap, len + 1);
    memcpy(p->name, id, len);
    p->name[len] = '\0';
    p->len = len;
    // 把标志符的名字加入到哈希表NameBuckets中
    p->link = NameBuckets[h];
    NameBuckets[h] = p;

    return p->name;
}

const char* Print2Buf(const char *format, ...)
{
    char buffer[FORMAT_PRINT_BUFFER_SIZE];
    va_list ap;

    va_start(ap, format);
    int ret = vsnprintf(buffer, FORMAT_PRINT_BUFFER_SIZE, format, ap);
    va_end(ap);
    if (ret < 0) {
        LOGE("vsnprintf() return error(%d)", ret);
        exit(EXT_UnknowErr);
    } else if (ret >= FORMAT_PRINT_BUFFER_SIZE) {
        LOGE("The buffer size vsnprintf() need is %d, but we given is %d", ret + 1, FORMAT_PRINT_BUFFER_SIZE);
    }

    return InternName(buffer, -1);
}
